﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Xml.Serialization;
using System.Runtime.Serialization;

namespace MazeWars
{
    public class TreeCreationWindow : Window
    {
        Rectangle menuDestRect, mapDestRect;
        List<Trunk> trunkList;
        List<Trunk> createdTree;
        Trunk selectedTrunk;
        Texture2D tileTex;
        Viewport menuViewport, treeViewport;
        bool menuOpen;
        int menuWidth;
        int menuCursorPos;
        Point[] menuItemOffset;
        Vector2 offset;
        Vector2 firstOffset;
        Vector2[] orthVec;

        const int MAX_ITEMS = 3;

        public TreeCreationWindow()
        {
            menuOpen = false;
            trunkList = loadTrunks();
            menuCursorPos = 0;
            menuDestRect = new Rectangle(0, 0, 32, 32);
            mapDestRect = new Rectangle(0, 0, 32, 32);
            menuItemOffset = new Point[MAX_ITEMS];
            createdTree = new List<Trunk>();
            orthVec = new Vector2[4];
            orthVec[0] = new Vector2(0, 64);
            orthVec[1] = new Vector2(64, 0);
            orthVec[2] = new Vector2(0, -64);
            orthVec[3] = new Vector2(-64, 0);
        }

        public override void setupWindow(ContentManager cm, Viewport vp)
        {
            tileTex = cm.Load<Texture2D>("Alpha_TilePallet");
            menuViewport = vp;
            treeViewport = vp;
            menuViewport.Width = 0;
            menuWidth = vp.Width / 3;
            offset = new Vector2(vp.Width / 2, vp.Height / 2);
            menuItemOffset[0] = new Point(10, menuViewport.Height / 4);
            menuItemOffset[1] = new Point(10, menuViewport.Height * 2 / 4);
            menuItemOffset[2] = new Point(10, menuViewport.Height * 3 / 4);
        }

        public override void draw(SpriteBatch sb, GraphicsDevice gd)
        {
            gd.Viewport = treeViewport;
            gd.Clear(Color.TransparentWhite);
            sb.Begin(SpriteBlendMode.AlphaBlend);

            if (createdTree.Count != 0)
            {
                foreach (Trunk t in createdTree)
                {
                    foreach (Tile tile in t.TrunkTiles)
                    {
                        mapDestRect.X = (int)(tile.X / 2 + firstOffset.X + t.Offset.X / 2);
                        mapDestRect.Y = (int)(tile.Y / 2 + firstOffset.Y + t.Offset.Y / 2);
                        sb.Draw(tileTex, mapDestRect, tile.SrcRect, Color.White);
                    }
                }
            }

            if (selectedTrunk != null)
            {
                foreach (Tile tile in selectedTrunk.TrunkTiles)
                {
                    mapDestRect.X = (int)(tile.X / 2 + offset.X);
                    mapDestRect.Y = (int)(tile.Y / 2 + offset.Y);
                    sb.Draw(tileTex, mapDestRect, tile.SrcRect, Color.White);
                }
            }
            sb.End();

            gd.Viewport = menuViewport;
            gd.Clear(Color.TransparentWhite);
            sb.Begin(SpriteBlendMode.AlphaBlend);
            for(int i = menuCursorPos; i < menuCursorPos + MAX_ITEMS; i++)
            {
                if (i >= trunkList.Count)
                {
                    continue;
                }
                foreach (Tile tile in trunkList[i].TrunkTiles)
                {
                    menuDestRect.X = (int)tile.X / 2 + menuItemOffset[i - menuCursorPos].X;
                    menuDestRect.Y = (int)tile.Y / 2 + menuItemOffset[i - menuCursorPos].Y;
                    sb.Draw(tileTex, menuDestRect, tile.SrcRect, Color.White); 
                }
            }
            sb.End();
        }

        public override void update(KeyboardState ks, GameTime gameTime)
        {
            if (menuOpen && menuViewport.Width < menuWidth)
            {
                menuViewport.Width += 10;
                if (menuViewport.Width > menuWidth)
                {
                    menuViewport.Width = menuWidth;
                }
            }
            else if (!menuOpen && menuViewport.Width > 0)
            {
                menuViewport.Width -= 10;
                if (menuViewport.Width < 0)
                {
                    menuViewport.Width = 0;
                }
            }

            if (ks.IsKeyDown(Keys.Q) && prevState.IsKeyUp(Keys.Q))
            {
                saveTrunks();
                selectedTrunk = null;
                createdTree.Clear();
                WindowManager.instance().changeWindow(Window.TITLE_WINDOW);
            }

            if (ks.IsKeyDown(Keys.M) && prevState.IsKeyUp(Keys.M))
            {
                menuOpen = !menuOpen;
            }

            if (ks.IsKeyDown(Keys.Enter) && prevState.IsKeyUp(Keys.Enter))
            {
                if (menuOpen)
                {
                    selectedTrunk = new Trunk(trunkList[menuCursorPos]);
                    menuOpen = false;
                }
                else if (!menuOpen && selectedTrunk != null)
                {
                    if (createdTree.Count > 0)
                    {
                        Point p = new Point((int)(offset.X - firstOffset.X) * 2, (int)(offset.Y - firstOffset.Y) * 2);
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < createdTree.Count; j++)
                            {
                                foreach (Tile t in createdTree[j].TrunkTiles)
                                {
                                    if (selectedTrunk == null)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        Vector2 temp = selectedTrunk.TrunkTiles[0].Pos + orthVec[i];
                                        temp.X += p.X;
                                        temp.Y += p.Y;

                                        Vector2 temp2 = new Vector2(t.X + createdTree[j].Offset.X, t.Y + createdTree[j].Offset.Y);
                                        if (temp == temp2 && t.Type % 2 == 1 && t.AttachedBranch == 0)
                                        {
                                            selectedTrunk.Offset = p;
                                            t.AttachedBranch = createdTree.Count;
                                            createdTree.Add(selectedTrunk);
                                            selectedTrunk = null;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (selectedTrunk.SpellID == -1)
                        {
                            createdTree.Add(selectedTrunk);
                            selectedTrunk = null;
                            firstOffset = new Vector2(offset.X, offset.Y);
                        }
                    }
                }
            }

            if (ks.IsKeyDown(Keys.Up) && prevState.IsKeyUp(Keys.Up))
            {
                if (menuOpen)
                {
                    menuCursorPos--;
                    if (menuCursorPos < 0)
                    {
                        menuCursorPos++;
                    }
                }
                else if (selectedTrunk != null)
                {
                    offset.Y -= 32;
                }
            }

            if (ks.IsKeyDown(Keys.Down) && prevState.IsKeyUp(Keys.Down))
            {
                if (menuOpen)
                {
                    menuCursorPos++;
                    if (menuCursorPos > trunkList.Count - 1)
                    {
                        menuCursorPos--;
                    }
                }
                else if (selectedTrunk != null)
                {
                    offset.Y += 32;
                }
            }

            if (ks.IsKeyDown(Keys.Left) && prevState.IsKeyUp(Keys.Left))
            {
                if (selectedTrunk != null)
                {
                    offset.X -= 32;
                }
            }

            if (ks.IsKeyDown(Keys.Right) && prevState.IsKeyUp(Keys.Right))
            {
                if (selectedTrunk != null)
                {
                    offset.X += 32;
                }
            }
            prevState = ks;
        }

        public override void loadWindow()
        {
            menuOpen = false;
            menuCursorPos = 0;
        }

        private List<Trunk> loadTrunks()
        {
            List<Trunk> tempList = new List<Trunk>();
            FileStream file = OpenTitleFile("testTrunks.xml", FileMode.Open);

            if (file != null)
            {
                try
                {
                    XmlSerializer xml = new XmlSerializer(typeof(List<Trunk>));
                    tempList = (List<Trunk>)xml.Deserialize(file);
                }
                catch (SerializationException e)
                {
                    byte[] errorMsg = new byte[128];
                    for (int i = 0; i < e.Message.Length; i++)
                    {
                        errorMsg[i] = (byte)e.Message[i];
                    }
                    FileStream error = OpenTitleFile("error.txt", FileMode.Create);
                    error.Write(errorMsg, 0, e.Message.Length > 128 ? 128 : e.Message.Length);
                    error.Close();

                    throw;
                }
                finally
                {
                    file.Close();
                }
            }
            return tempList;
        }

        private void saveTrunks()
        {
            FileStream file = OpenTitleFile("trunks.xml", FileMode.Create);

            if (file != null)
            {
                try
                {
                    XmlSerializer xml = new XmlSerializer(typeof(List<Trunk>));
                    xml.Serialize(file, createdTree);
                    
                }
                catch (SerializationException e)
                {
                    byte[] errorMsg = new byte[128];
                    for (int i = 0; i < e.Message.Length; i++)
                    {
                        errorMsg[i] = (byte)e.Message[i];
                    }
                    FileStream error = OpenTitleFile("error.txt", FileMode.Create);
                    error.Write(errorMsg, 0, e.Message.Length > 128 ? 128 : e.Message.Length);
                    error.Close();

                    throw;
                }
                finally
                {
                    file.Close();
                }
            }
        }

        private static FileStream OpenTitleFile(string filename, FileMode mode)
        {
            string fullpath = Path.Combine(StorageContainer.TitleLocation, filename);

            if (mode != FileMode.Create)
            {
                if (!File.Exists(fullpath))
                {
                    return null;
                }
            }

            return File.Open(fullpath, mode);
        }
    }//End of class TreeCreationWindow
}
